package com.vecspace.web.freemarker;

import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReentrantReadWriteLock;

import com.vecspace.utils.FileHelper;
import com.vecspace.utils.log.HLogger;

import freemarker.cache.TemplateLoader;

/**Freemarker的模版加载类，用于读取模版内容
 * @author: wanghua
 */
public class StringTemplateLoader implements TemplateLoader {
	private static final String DEFAULT_TEMPLATE_KEY = "_dayu_frmk_template_key_";
	private Map<String,String> templates = new HashMap<>();
	ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
	private static boolean useCache;
	public StringTemplateLoader() {
		
	}

	public void setDefaultTemplate(String defaultTemplate){
		if (defaultTemplate != null && !defaultTemplate.equals("")) {
			templates.put(DEFAULT_TEMPLATE_KEY, defaultTemplate);
		}
	}
	
	public void AddTemplate(String name, String template) {
		if (name == null || template == null || name.equals("")|| template.equals("")) {
			return;
		}
		if (!templates.containsKey(name)) {
			templates.put(name, template);
		}
	}

	@Override
	public void closeTemplateSource(Object templateSource)throws IOException {

	}
	
	/**freemarker会自动将模版名上加上本地化标识符，将其去除。
	 * 
	 * @param name
	 * @return 
	 * @author: wanghua
	 */
	private String replaceLocale(String name){
		if(name.endsWith("_zh_CN") || name.endsWith("_zh_cn")){
			name = name.substring(0, name.length()-6);
		}else if(name.endsWith("_zh_CN.ftl") || name.endsWith("_zh_cn.ftl")){
			name = name.substring(0, name.length()-10)+".ftl";
		}else if(name.endsWith("_zh_CN.class") || name.endsWith("_zh_cn.class")){
			name = name.substring(0, name.length()-12)+".class";
		}else if(name.endsWith("_zh")){
			name = name.substring(0, name.length()-3);
		}else if(name.endsWith("_zh.ftl")){
			name = name.substring(0, name.length()-7)+".ftl";
		}else if(name.endsWith("_en_US") ||name.endsWith("_en_us")){
			name = name.substring(0, name.length()-6)+".ftl";
		}else if(name.endsWith("_en_US.ftl") ||name.endsWith("_en_us.ftl")){
			name = name.substring(0, name.length()-10)+".ftl";
		}else if(name.endsWith("_en_US.class") ||name.endsWith("_en_us.class")){
			name = name.substring(0, name.length()-12)+".class";
		}else if(name.endsWith("_en")){
			name = name.substring(0, name.length()-3);
		}else if(name.endsWith("_en.ftl")){
			name = name.substring(0, name.length()-7)+".ftl";
		}
		return name;
	}
	/**获取模版内容
	 * @param filePath
	 * @return
	 * @throws IOException 
	 * @author: wanghua
	 */
	@Override
	public Object findTemplateSource(String name) throws IOException {		
 		if (name == null || name.equals("")) {
			name = DEFAULT_TEMPLATE_KEY;
		}
		name = replaceLocale(name);
		String template = null;
		
		lock.readLock().lock();
		try{
			if(useCache)template = templates.get(name);
		}finally{
			lock.readLock().unlock();
		}
		
		if(template == null){
			lock.writeLock().lock();
			try{
				String pageId = null;
				String filePath="";
				String className = null;
				
				if(name.startsWith("ftl:")){
					name = name.substring(4);
				}
				String[] attrs = name.split("&");
				for(String attr : attrs){//从 name 中解析关键字，包括pageId  filePath className等
					String[] kv = attr.split("=");
					if(kv.length == 1){
						filePath = kv[0];
					}else if(kv.length == 2){
						if("pageId".equalsIgnoreCase(kv[0])){
							pageId = kv[1].trim();
						}else if("className".equalsIgnoreCase(kv[0])){
							className = kv[1].trim();
						}
					}
				}
				if(pageId != null && pageId.length() > 0){//如果pageId存在，则从缓存（StringTemplateCache）中获取模版文件
					template = StringTemplateCache.instance().getTemplate(pageId);
				}else{
					if(!filePath.startsWith("/")) filePath = "/" + filePath;					
					if(className == null || className.length() == 0){
						try{							
							template = loadTemplate(filePath);//根据文件路径，读取文件内容
						}catch(Exception e){
							
						}
					}else{
						try {
							Class<?> clazz = Class.forName(className);
							try{
								template = loadTemplate(clazz, filePath);//读取clazz所在的jar中的filePath所代表的文件
							}catch(Exception e){
								
							}
						} catch (Exception e) {
							try{
								template = loadTemplate(filePath);
							}catch(Exception e2){
								
							}
						}
					}
				}
				templates.put(name, template);
			}finally{
				lock.writeLock().unlock();
			}
		}
		return template;
	}
	/**根据文件路径，读取文件内容。同时将文件内容进行缓存，后续直接从缓存中读取
	 * @param filePath
	 * @return
	 * @throws IOException 
	 * @author: wanghua
	 */
	private String loadTemplate(String filePath) throws IOException{
		String filePathKey = "ftl:"+filePath;
		String template = FileContentCache.DEFAULT().get(filePathKey);
		if(template == null){
			synchronized (this.getClass()) {
				template = FileContentCache.DEFAULT().get(filePathKey);
				if(template == null){
					try{
						template = FileHelper.readFileText(filePath);
					}catch(Exception e){
						HLogger.DEFAULT().info(filePath + "不是一个单独的文件资源");
					}
					if(template != null && template.length() > 0){
						FileContentCache.DEFAULT().put(filePathKey, template);
					}
				}
			}			
		}
		return template;
	}
	
	/**
	 * 根据文件路径，读取文件内容。同时将文件内容进行缓存，后续直接从缓存中读取
	 * @param clazz 读取clazz所在的jar中的文件
	 * @param filePath
	 * @return
	 * @throws Exception 
	 * @author: wanghua
	 */
	private String loadTemplate(Class<?> clazz, String filePath) throws Exception{
		String filePathKey = "ftl:"+clazz.getName()+":"+filePath;
		String template = FileContentCache.DEFAULT().get(filePathKey);
		if(template == null){
			synchronized (this.getClass()) {
				template = FileContentCache.DEFAULT().get(filePathKey);
				if(template == null){
					template = FileHelper.readFileText(clazz, filePath);
					FileContentCache.DEFAULT().put(filePathKey, template);
				}
			}			
		}
		return template;
	}

	@Override
	public long getLastModified(Object templateSource) {
		return 0;
	}
	
	@Override
	public Reader getReader(Object templateSource, String encoding) throws IOException {
		return new StringReader((String) templateSource);
	}

	public boolean isUseCache() {
		return useCache;
	}

	public void setUseCache(boolean useCache) {
		StringTemplateLoader.useCache = useCache;
	}
	
	
}
